/*******************************************************************************
 * Copyright (c) 2012, 2013 XML-Print Project.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     XML-Print Project - initial API and implementation
 ******************************************************************************/
package info.xmlprint.core.mapping;

import info.xmlprint.core.xml.PElement;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

/*
 * beschreibt Postion eines Elementes,
 */
public class ElementPath implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 3252931171867997856L;

	private ElementPathNode currPathNode;

	private Set<ElementPathNode> set = new HashSet<ElementPathNode>();;

	private int elementType = -1;

	public ElementPath() {
	};

	public ElementPathNode[] getPElements() {
		return set.toArray(new ElementPathNode[0]);
	}

	public int getElementType() {
		return elementType;

	}

	public void setElementType(int i) {
		this.elementType = i;
	}

	public void addNode(ElementPathNode parent, ElementPathNode pn) {
		if (parent != null) {
			set.add(parent);
			parent.setInElementPath(this);
			parent.addChildren(pn);
		}
		set.add(pn);
		pn.setInElementPath(this);

	}

	public void removeNode(ElementPathNode pn) {
		if (pn.equals(currPathNode))
			return;

		if (isBefore(pn)) {
			removeParent(pn);
		} else
			removeChildren(pn);

	}

	private void removeParent(ElementPathNode pn) {
		for (ElementPathNode p : pn.getChildrens()) {
			p.setParent(null);
		}

		if (pn.getParent() != null) {
			removeParent(pn.getParent());
		}
		set.remove(pn);
		pn.setInElementPath(null);
	}

	private void removeChildren(ElementPathNode pn) {
		if (pn.getParent() != null) {
			pn.getParent().removeChildren(pn);
		}

		for (ElementPathNode p : pn.getChildrens()) {
			removeChildren(p);
		}
		set.remove(pn);
		pn.setInElementPath(null);
	}

	private boolean isBefore(ElementPathNode pn) {
		ElementPathNode startNode = currPathNode;
		while (startNode != null) {
			if (startNode.equals(pn))
				return true;
			startNode = startNode.getParent();
		}

		return false;

	}

	public void setCurrPElementNode(ElementPathNode currPElementNode) {
		this.currPathNode = currPElementNode;
	}

	public ElementPathNode getCurrPathNode() {
		return currPathNode;
	}

	public int getCurrIndex() {
		int i = 0;
		ElementPathNode start = currPathNode;
		while (start.getParent() != null) {
			i++;
			start = start.getParent();
		}
		return i;
	}

	public void setcurrPathNode(ElementPathNode currPathNode) {
		this.currPathNode = currPathNode;
	}

	public ElementPathNode getRoot() {

		for (ElementPathNode pn : set.toArray(new ElementPathNode[0])) {
			if (pn.getParent() == null)
				return pn;
		}
		return null;
	}

	public void toPrint() {

		for (ElementPathNode pn : set.toArray(new ElementPathNode[0])) {
			// System.out.println(pn.getPElement().getName()
			// + (pn.getParent() == null ? " null" : " "
			// + pn.getParent().getPElement().getName()));
		}
	}

	public String getSimplePathString(boolean addRoot) {

		ElementPathNode root = getRoot();
		String s = "";
		if (addRoot)
			s = root.getPElement().getName();

		while (root.hasChildren()) {
			ElementPathNode childrenNode = root.getChildrens()[0];
			s += "/" + childrenNode.getPElement().getName();
			root = childrenNode;
		}

		return s;
	}

	public String getFullPathString() {
		String pathStr = "";
		ElementPathNode root = getRoot();
		pathStr = root.getPElement().getName() + getAttrVal(root);

		while (root.hasChildren()) {
			ElementPathNode childrenNode = root.getChildrens()[0];
			pathStr += "/" + childrenNode.getPElement().getName()
					+ getAttrVal(childrenNode);
			root = childrenNode;
		}

		if (!pathStr.equals(""))
			pathStr = "//" + pathStr;
		// pathStr = pathStr.replaceAll("^/", "//");

		return pathStr;
	}

	private String getAttrVal(ElementPathNode epn) {
		String attrVal = "";
		for (String attr : epn.getAttribut()) {
			if (epn.isSelectAll(attr)) {
				attrVal += " or @" + attr;
			} else
				for (String val : epn.getAttributValue(attr)) {
					attrVal += " or @" + attr + "='" + val + "'";
				}
		}

		attrVal = attrVal.trim();
		attrVal = attrVal.replaceFirst("or", "").trim();

		if (!attrVal.equals(""))
			attrVal = "[" + attrVal + "]";
		return attrVal;
	}

	public static void main(String args[]) throws IOException,
			ClassNotFoundException {
		ElementPath ef = new ElementPath();

		ElementPathNode pn1 = new ElementPathNode(new PElement("p1"));
		ef.addNode(null, pn1);
		ef.setcurrPathNode(pn1);

		ByteArrayOutputStream out = new ByteArrayOutputStream();
		ObjectOutputStream p = new ObjectOutputStream(out);

		p.writeObject(ef);
		p.flush();

		InputStream in = new ByteArrayInputStream(out.toByteArray());
		ObjectInputStream oi = new ObjectInputStream(in);
		ElementPath new_ef = (ElementPath) oi.readObject();

		ElementPathNode pn2 = new ElementPathNode(new PElement("p2"));
		ef.addNode(pn1, pn2);

		// new_ef.toPrint();
		PElement p1 = ef.getCurrPathNode().getPElement();
		PElement new_p1 = new_ef.getCurrPathNode().getPElement();

		// System.out.println(p1.equals(new_p1));

		// ef.toPrint();

	}

	public Set<ElementPathNode> getSet() {
		return set;
	}

}
